using System;
using System.Text;
using Lidgren.Network;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SolarWinds.Layouts;
using SolarWinds.Widgets;

namespace SolarWinds.Screens
{
    class LobbyScreen : Screen
    {
        private readonly WidgetManager mWidgetManager;
        private IScreenManagerService mScreenManager;

        private static NetPeer sPeer;
        private static NetBuffer sReadBuffer;
        private static int sPort = 12131;

        private Window mChatWindow;

        private TextBox mChatTextBox;
        private Label mChatTextList;

        private Label mPlayerList;
        private Label mServerList;
        private PushButton mHostGameButton;
        private PushButton mJoinGameButton;

        public LobbyScreen(Game game)
            : base(game)
        {
            mWidgetManager = new WidgetManager(game);
            Components.Add(mWidgetManager);

            BlocksDraw = false;
            BlocksUpdate = false;
        }

        public override void Initialize()
        {
            mScreenManager = (IScreenManagerService)
                             Game.Services.GetService(typeof(IScreenManagerService));
            
            base.Initialize();

            #region Widgets

            mChatWindow = new Window(Game)
                          {
                                Position = new Point(40, 40),
                                Caption = "Chat Window",
                                Width = GraphicsDevice.Viewport.Width - 180,
                                Height = GraphicsDevice.Viewport.Height - 180,
                                Moveable = false,
                                Resizeable = false,
                                HasCloseButton = false,
                                Tabable = false
                          };
            mWidgetManager.AddChild(mChatWindow);

            mChatTextList = new Label(Game)
                            {
                                Position = new Point(20, 20),
                                Width = mChatWindow.Width - 40,
                                Height = mChatWindow.Height - 40 - 36,
                                Caption = ""

                            };
            mChatWindow.AddChild(mChatTextList);

            mChatTextBox = new TextBox(Game)
                               {
                                   Position = new Point(20, mChatTextList.Height + 40),
                                   Height = 16,
                                   Width = mChatWindow.Width - 40
                               };
            mChatTextBox.EnterPressed += new EventHandler(mChatTextBox_EnterPressed);
            mChatWindow.AddChild(mChatTextBox);

            #endregion

            #region Network

            WriteToConsole("Type 'connect <host> <port>' to connect to another peer,\n or 'connect <port>' to connect to another localhost peer");

            var config = new NetConfiguration("p2pchat");
            config.MaxConnections = 256;
            config.Port = sPort;
            sPeer = new NetPeer(config);
            //s_peer.VerboseLog = true;

            sPeer.SetMessageTypeEnabled(
                NetMessageType.ConnectionRejected | 
                NetMessageType.BadMessageReceived | 
                NetMessageType.VerboseDebugMessage, true);

            // start listening for incoming connections
            sPeer.Start();

            // create a buffer to read data into
            sReadBuffer = sPeer.CreateBuffer();

            sPeer.DiscoverLocalPeers(sPort);
            
            #endregion
        }

        void mChatTextBox_EnterPressed(object sender, EventArgs e)
        {
            string text = mChatTextBox.Value;
            SendString(text);
            mChatTextBox.Value = "";
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);

            sPeer.Shutdown("Application exiting");
        }

        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);
        
            // update network
            NetMessageType type;
            NetConnection source;
            while (sPeer.ReadMessage(sReadBuffer, out type, out source))
            {
                HandleMessage(type, source, sReadBuffer);                
            }
        }

        private void HandleMessage(NetMessageType type, NetConnection source, NetBuffer buffer)
        {
            switch (type)
            {
                case NetMessageType.StatusChanged:
                    if (source.LocalHailData == null)
                        source.LocalHailData = Encoding.ASCII.GetBytes("Hi; I'm " + sPeer.GetHashCode());
                    if (source.RemoteHailData != null)
                        WriteToConsole("New status: " + source.Status + " - remote hail is: " + Encoding.ASCII.GetString(source.RemoteHailData));
                    else
                        WriteToConsole("New status: " + source.Status + " - remote hail is null");
                    break;
                case NetMessageType.DebugMessage:
                case NetMessageType.VerboseDebugMessage:
                case NetMessageType.BadMessageReceived:
                case NetMessageType.ConnectionRejected:
                    WriteToConsole(buffer.ReadString());
                    break;
                case NetMessageType.Data:
                    WriteToConsole(source.RemoteEndpoint + " writes: " + buffer.ReadString());
                    break;
                case NetMessageType.ServerDiscovered:
                    // discovered another peer!
                    sPeer.Connect(buffer.ReadIPEndPoint(), Encoding.ASCII.GetBytes("Hi; I'm " + sPeer.GetHashCode()));
                    break;
                default:
                    // unhandled
                    break;
            }
        }

        private void WriteToConsole(string text)
        {
            mChatTextList.Caption += (text + Environment.NewLine);
        }

        static void SendString (string str)
        {
            if (str == "discover")
            {
                sPeer.DiscoverLocalPeers(sPort);
                return;
            }

            NetBuffer buffer = sPeer.CreateBuffer();
            buffer.Write(str);

            // send to all other peers
            sPeer.SendToAll(buffer, NetChannel.ReliableUnordered);
        }

    }
}